package presentation.rest;

import com.sun.jersey.spi.resource.Singleton;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import presentation.twitter.Comment;
import presentation.twitter.Tweet;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Singleton
@Path("tweets/streaming")
public class TweetStreamingResource {

	private final static Logger logger = LoggerFactory.getLogger(TweetStreamingResource.class);


	@GET
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}/stream")
	@Produces({MediaType.APPLICATION_JSON, ServiceLocator.MEDIA_TYPE_X_JAVASCRIPT})
	public Response stream(
			@Context HttpHeaders headers,
			@PathParam("username") String username,
			@QueryParam("callback") @DefaultValue("stream") String callback
	) {

		final List<Tweet> entity = ServiceLocator.TWITTER.findStream(username);
		logger.info("Found stream username = {}.", username);

		TweetStreamingOutput streamingOutput = TweetStreamingOutput.newBuilder()
				.setEntity(entity)
				.build();

		return ResponseBuilder.newBuilder()
				.setHeaders(headers)
				.setCallback(callback)
				.setEntity(streamingOutput)
				.build();
	}

	@GET
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}")
	@Produces({MediaType.APPLICATION_JSON, ServiceLocator.MEDIA_TYPE_X_JAVASCRIPT})
	public Response tweets(
			@Context HttpHeaders headers,
			@PathParam("username") String username,
			@QueryParam("callback") @DefaultValue("stream") String callback
	) {
		final List<Tweet> entity = ServiceLocator.TWITTER.findTweets(username);
		logger.info("Found tweets username = {}.", username);

		TweetStreamingOutput streamingOutput = TweetStreamingOutput.newBuilder()
				.setEntity(entity)
				.build();

		return ResponseBuilder.newBuilder()
				.setHeaders(headers)
				.setCallback(callback)
				.setEntity(streamingOutput)
				.build();
	}

	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public Response create(final InputStream inputStream) throws IOException {

		JsonParser jp = ServiceLocator.JSON_FACTOR.createJsonParser(inputStream);

		Tweet.Builder tweet = Tweet.newBuilder();
		jp.nextToken();

		JsonToken token;
		while ((token = jp.nextToken()) != null && token != JsonToken.END_OBJECT) {
			String fieldName = jp.getCurrentName();
			jp.nextToken();

			if ("username".equals(fieldName)) {
				tweet.setUsername(jp.getText());
			} else if ("message".equals(fieldName)) {
				tweet.setMessage(jp.getText());
			} else if ("date".equals(fieldName)) {
				tweet.setDate(new Date(jp.getLongValue()));
			}
		}

		ServiceLocator.TWITTER.addTweet(tweet);
		logger.info("Created tweet = {}.", tweet);

		return Response.ok().build();
	}

	@PUT
	@Path("{tweetId}")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response update(@PathParam("tweetId") long tweetId, InputStream inputStream) throws IOException {

		JsonParser jp = ServiceLocator.JSON_FACTOR.createJsonParser(inputStream);

		Comment.Builder comment = Comment.newBuilder();
		comment.setTweetId(tweetId);

		jp.nextToken();

		JsonToken token;
		while ((token = jp.nextToken()) != null && token != JsonToken.END_OBJECT) {
			String fieldName = jp.getCurrentName();
			jp.nextToken();

			if ("username".equals(fieldName)) {
				comment.setUsername(jp.getText());
			} else if ("comment".equals(fieldName)) {
				comment.setComment(jp.getText());
			} else if ("date".equals(fieldName)) {
				comment.setDate(new Date(jp.getLongValue()));
			}
		}

		ServiceLocator.TWITTER.addComment(comment.build());
		logger.info("Created tweet with comment = {}", comment);
		return Response.ok().build();
	}

	@DELETE
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}")
	public Response remove(@PathParam("username") String username) {
		ServiceLocator.TWITTER.removeUsername(username);
		logger.info("Removed username = {}.", username);
		return Response.ok(Response.Status.OK).build();
	}

	@POST
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}/follow")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response follow(@PathParam("username") String username, InputStream inputStream) throws IOException {

		JsonParser jp = ServiceLocator.JSON_FACTOR.createJsonParser(inputStream);

		final List<String> usernames = new ArrayList<String>();
		jp.nextToken();

		JsonToken token;
		while ((token = jp.nextToken()) != null && token != JsonToken.END_ARRAY) {
			jp.nextToken();
			usernames.add(jp.getText());
		}

		ServiceLocator.TWITTER.follow(username, usernames);
		logger.info("Username = {} will follow:  {}.", username, usernames);
		return Response.ok().build();
	}
}
